package com.shujia;

import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentTypeException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import org.apache.hadoop.io.IntWritable;

/**
 * 需求：传入一个字符串，返回字符串的长度
 *  SELECT mylength("111111") => 6
 *
 *  add jar /usr/local/soft/jars/hiveCode-1.0.jar;
 *  create temporary function mylength as 'com.shujia.NewUDF';
 */

@Description(
 value = "SELECT mylength('111111’) => 6 get string length"
 ,name = "mylength"
)
// 注意：在UDF函数中也可以引用其他Jar包 corn   * * * * *
public class NewUDF extends GenericUDF {

    /**
     * 该函数表示，当函数被调用时，需要进行实例化操作，在该函数中，可以对参数的数量及类型进行判断
     * @param arguments 表示为传入的参数
     * @return
     * @throws UDFArgumentException
     */
    @Override
    public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
        // 当传入的参数长度不符合要求，抛出异常
        if(arguments.length!= 1){
            throw new UDFArgumentLengthException("当前参数的长度为1,您传入的参数个数为："+arguments.length);
        }
        /**
         *  自定义函数的参数类型：
         *      PRIMITIVE, 表示为一般数据类型，在HIVE中有 STRING，INT，DATE 等
         *      LIST, 表示HIVE中的Array数据类型
         *      MAP, 表示HIVE中的Map数据类型
         *      STRUCT 表示HIVE中的STRUCT数据类型
         */

        // 当传入的参数类型不符合，那么可以抛出类型异常
        if(!arguments[0].getCategory().equals(ObjectInspector.Category.PRIMITIVE)){
            throw new UDFArgumentTypeException(1,"当前参数类型不符合要求...");
        }

        // 由于当前需求要求函数的返回值为一个int类型，那么可以选择Java中的Int作为其返回类型
//        return PrimitiveObjectInspectorFactory.javaIntObjectInspector;
        // 当返回值类型为Hadoop中的参数类型时，需要选择writable标记的类型，该类型序列化后大小较小，运行速度相对会快一点
        return  PrimitiveObjectInspectorFactory.writableIntObjectInspector;
    }

    /**
     * 该函数中可以写具体的执行逻辑
     * @param arguments
     * @return
     * @throws HiveException
     */
    @Override
    public Object evaluate(DeferredObject[] arguments) throws HiveException {
        // 由于传入参数只有一个，所以通过取下标为0 获取第一个参数对象，再通过get函数获取其对应的值
        String col = arguments[0].get().toString();
        return new IntWritable(col.length());
    }

    @Override
    public String getDisplayString(String[] children) {
        return "nothing todo...";
    }
}
